package token

import (
    "crypto/rsa"
	"github.com/dgrijalva/jwt-go"
	"io/ioutil"
	"time"
	"errors"
)

type MyCustomClaims struct {
	Id int64 `json:"id"`
	Name string `json:"name"`
	jwt.StandardClaims
}

var publicKey *rsa.PublicKey

func init(){
	publicKey = LoadRSAPublicKeyFromDisk("public.pem")
}

func ValidateToken(tokenString string) (*MyCustomClaims, error){
	//使用公钥解析并验证
	
	token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, func(token *jwt.Token)(interface{},error){
		return publicKey, nil
	})

	if token.Valid {
		//验证通过
		if claims, ok := token.Claims.(*MyCustomClaims); ok {
			//获取自定义的字段值、标准Claims的字段值
			// fmt.Printf("%v %v", claims.Foo, claims.StandardClaims.ExpiresAt)
			return claims, nil
		}else{
			return nil, errors.New("Couldn't handle this token.Claims")
		}
		
	} else if ve, ok := err.(*jwt.ValidationError); ok {
		if ve.Errors&jwt.ValidationErrorMalformed != 0 {
			return nil, errors.New("That's not even a token")
		} else if ve.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 {
			// Token is either expired or not active yet
			return nil, errors.New("Timing is everything")
		} else {
			return nil, errors.New("Couldn't handle this token:"+err.Error())
		}
	} else {
		return nil, errors.New("Couldn't handle this token:"+err.Error())
	}

}

func LoadRSAPrivateKeyFromDisk(location string) *rsa.PrivateKey {
	keyData, e := ioutil.ReadFile(location)
	if e != nil {
		panic(e.Error())
	}
	key, e := jwt.ParseRSAPrivateKeyFromPEM(keyData)
	if e != nil {
		panic(e.Error())
	}
	return key
}

func LoadRSAPublicKeyFromDisk(location string) *rsa.PublicKey {
	keyData, e := ioutil.ReadFile(location)
	if e != nil {
		panic(e.Error())
	}
	key, e := jwt.ParseRSAPublicKeyFromPEM(keyData)
	if e != nil {
		panic(e.Error())
	}
	return key
}

func MakeSampleToken(c jwt.Claims, key interface{}) string {
	token := jwt.NewWithClaims(jwt.SigningMethodRS256, c)
	s, e := token.SignedString(key)

	if e != nil {
		panic(e.Error())
	}

	return s
}

//return 1441006057 in sec
func GetTimestamp() int64 {
   return time.Now().Unix()
}